package com.adcc.loadsheet.billing.security;

import com.adcc.aoc.devLib.common.log.Log;
import com.adcc.loadsheet.billing.entity.PbStaffEntity;
import com.adcc.loadsheet.billing.entity.contractuser.ContractUserEntity;
import com.adcc.loadsheet.billing.entity.contractuser.ContractUserStaffEntity;
import com.adcc.loadsheet.billing.exception.PasswordException;
import com.adcc.loadsheet.billing.mapper.mysql.PbStaffEntityMapper;
import com.adcc.loadsheet.billing.mapper.mysql.contractuser.ContractUserEntityMapper;
import com.adcc.loadsheet.billing.mapper.mysql.contractuser.ContractUserStaffEntityMapper;
import com.adcc.loadsheet.billing.service.PermissionService;
import com.adcc.loadsheet.billing.util.EncodeUtil;
import com.adcc.loadsheet.billing.vo.permission.PermissionEntityVO;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.Map;

/**
 * 用户信息获取服务
 * Created by zhaoml on 2020-04-01.
 */
@Service
public class BillingUserDetailesService implements UserDetailsService {

    @Autowired
    PbStaffEntityMapper pbStaffEntityMapper;

    @Autowired
    ContractUserEntityMapper contractUserEntityMapper;

    @Autowired
    ContractUserStaffEntityMapper contractUserStaffEntityMapper;

    @Autowired
    PermissionService permissionService;

    // 获取用户信息，生成BillingUserDetails对象
    private BillingUserDetails getBillingUserDetails(PbStaffEntity pbStaffEntity, String username,String contractUserAbbrev) {
        boolean Superflag = false; // 是否为超级管理员
        boolean isContractUserFlag = false; //是否是合同用户
        // 判断当前用户是否为超级管理员
        Superflag = checkUserIsAdmin(pbStaffEntity, Superflag);

        List<PermissionEntityVO> permissionEntityVOList = Lists.newArrayList();
        if(Superflag){
            //超级管理员，获取全部权限
            permissionEntityVOList = permissionService.selectPermissions(null);
        }else {
            //普通用户，查已分配的权限
            Map<String, Object> map = Maps.newHashMap();
            List<ContractUserStaffEntity> contractUserStaffEntityList = contractUserStaffEntityMapper.selectByLoginId(pbStaffEntity.getPB_LOGIN_ID());
            if(contractUserStaffEntityList != null && contractUserStaffEntityList.size() > 0){  //合同用户
                map.put("contractUserId",contractUserStaffEntityList.get(0).getContractUserId());
                permissionEntityVOList = permissionService.selectPermissions(map);
            }
        }

        // 生成userinfo对象
        UserInfo userInfo = new UserInfo().setUserVO(username, Superflag,isContractUserFlag,contractUserAbbrev,permissionEntityVOList);
        // 返回UserDetails实现类
        return new BillingUserDetails(userInfo);
    }

    /**
     * 判断当前用户是否为超级管理员
     *
     * @param pbStaffEntity
     * @param superflag
     * @return
     */
    private boolean checkUserIsAdmin(PbStaffEntity pbStaffEntity, boolean superflag) {
        if (pbStaffEntity.getPB_IS_INNER_USER()==1) {
            superflag = true;
        }
        return superflag;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //通过用户名从数据库中获取用户
        PbStaffEntity pbStaffEntity = pbStaffEntityMapper.findByLoginId(username);

        //合同用户
        ContractUserEntity contractUserEntity = contractUserEntityMapper.findByLoginID(username);
        //合同用户简称
        String contractUserAbbrev = contractUserEntity == null ? "" : contractUserEntity.getUserAbbrev();
        return getBillingUserDetails(pbStaffEntity, username,contractUserAbbrev);
    }

    // 验证本地用户及判断用户是否锁定
    public LoginCheckAndLockResult checkLocalUserAndLock(String password, String username) throws PasswordException {
        LoginCheckAndLockResult loginCheckAndLockResult = locakCheckUsernameAndPassword(password, username);
        try {
            if (!checkLocalPassWord(password, username)) {
                throw new PasswordException("用户名或密码错误！");
            }
        } catch (Exception ex) {
            Log.error(BillingUserDetailesService.class, "用户名或密码错误", ex);
            throw ex;
        }
        return loginCheckAndLockResult;
    }

    private LoginCheckAndLockResult locakCheckUsernameAndPassword(String password, String username) {
        LoginCheckAndLockResult loginCheckAndLockResult = new LoginCheckAndLockResult();
        localCheckAndGetLockCount(password, username, loginCheckAndLockResult);
        return loginCheckAndLockResult;
    }

    /**
     * 本地校验用户信息是否合法，并获取当前用户锁定次数
     *
     * @param password
     * @param username
     * @param loginCheckAndLockResult
     */
    private void localCheckAndGetLockCount(String password, String username, LoginCheckAndLockResult loginCheckAndLockResult) {
        loginCheckAndLockResult.setCount(getLockCount(username));
        // 本地密码校验
        loginCheckAndLockResult.setLocalCheckOkflag(checkLocalPassWord(password, username));
    }

    private int getLockCount(String username) {
        int count = 0;
        //根据用户名查询用户
        PbStaffEntity pbStaffEntity = pbStaffEntityMapper.findByLoginId(username);
        // 判断用户是否存在
        if (pbStaffEntity == null) {
            throw new UsernameNotFoundException("用户名或密码错误！");
        }
        return count;
    }

    // 密码校验
    private boolean checkLocalPassWord(String password, String username) {
        try {
            if (getPwd(username).equals(EncodeUtil.sha1(password))) {
                return true;
            } else {
                return false;
            }
        }catch (NoSuchAlgorithmException e){
            Log.error(BillingUserDetailesService.class, "用户名或密码错误", e);
            return false;
        }
    }

    //获取密码
    private String getPwd(String name) throws PasswordException {
        //根据用户名从数据库查询密码
        PbStaffEntity pbStaffEntity = pbStaffEntityMapper.findByLoginId(name);
        if(pbStaffEntity != null){
            String res = pbStaffEntity.getPB_PASSWORD();
            return res;
        }
        return "";
    }

    // 本地验证结果与锁定次数校验
    class LoginCheckAndLockResult {
        public LoginCheckAndLockResult() {
        }

        boolean localCheckOkflag;  // 登录是否成功
        int count;                      // 失败次数

        public boolean isLocalCheckOkflag() {
            return localCheckOkflag;
        }

        public int getCount() {
            return count;
        }

        public void setLocalCheckOkflag(boolean localCheckOkflag) {
            this.localCheckOkflag = localCheckOkflag;
        }

        public void setCount(int count) {
            this.count = count;
        }
    }
}